home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
(A)U
/
(A)U2.ADF
/
PcView
/
VIEW.C
< prev
next >
Wrap
Text File
|
1989-06-03
|
15KB
|
505 lines
/* ViewPC - IFF File Viewer - (c) 1988 Dallas John Hodgson
This program must be compiled under memory model "compact" or larger in
order to fetch the correct allocation libraries. This is to avoid problems
when loading in pictures of 64K in size. View requires the library
"EGAVGA.obj" to be linked in at compile time.
Compiled under Turbo C 1.5
SHAREWARE IS FOR THE PUBLIC GOOD. SUPPORT IT!
*/
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <graphics.h>
#include "view.h"
#define SafeRead(file,buf,len) if (!fread(buf,len,1,file)) { puts("disk error!"); fclose(file); return(NULL); }
/* The following routines are required because Intel machines are little-endian;
i.e., constants are stored in reverse order. Since the IFF spec was
originally designed for Motorola CPU's, ANY time we read a numerical
value larger than a char we had better reverse the result! */
#define REVERSE(a) Reverse_Constant(&a,sizeof(a))
struct Screen screen;
char planes[MAXPLANES][LINELEN];
int ega_remap[256],
debug,
scaling=1, /* scaling ON by default */
remap=1, /* remapping ON by default */
pal=1; /* palette zapping allowed by default */
struct palettetype palette; /* used to hold our default palette */
/* RGB 2-bit analog to EGA palette remap tables */
static char r_map[4] = { 0,32,4,36 },
g_map[4] = { 0,16,2,18 },
b_map[4] = { 0,8,1,9 };
/************************************************************************
* *
* Routine name(s) : ReadILBM() *
* Author : D. John Hodgson *
* Environment : Turbo "C" 1.5, small model *
* *
* ReadILBM attempts to read an IFF ILBM file into memory. Returns *
* a screen pointer if successful, otherwise NULL. *
* *
* LIMITATIONS : no CATS/LISTS/PROPS. CAMG chunks,masking supported. *
************************************************************************/
struct Screen *ReadILBM(fspec)
char *fspec; /* MS-DOS filename */
{
FILE *fp;
BitMapHeader bmhd;
Chunk header;
long id;
int i;
if (!(fp=fopen(fspec,"rb"))) {
puts("Error opening file.");
return(NULL);
}
SafeRead(fp,&header,sizeof(header));
if (header.ckID!=ID_FORM) { fclose(fp); return(NULL); }
SafeRead(fp,&id,sizeof(id));
if (id!=ID_ILBM) { fclose(fp); return(NULL); }
for (;;) {
SafeRead(fp,&header,sizeof(header));
REVERSE(header.ckSize);
if (header.ckID==ID_BODY) break;
switch(header.ckID) {
case ID_BMHD: SafeRead(fp,&bmhd,sizeof(bmhd));
REVERSE(bmhd.w);
REVERSE(bmhd.h);
REVERSE(bmhd.x);
REVERSE(bmhd.y);
break;
case ID_CMAP: SafeRead(fp,&screen.colormap[0][0],header.ckSize);
screen.colors=header.ckSize/3;
break;
case ID_CAMG: SafeRead(fp,&screen.ViewModes,header.ckSize);
REVERSE(screen.ViewModes);
break;
/* skip unknown ID's */
default: fseek(fp,ROUNDODDUP(header.ckSize),SEEK_CUR);
}
}
/* ID_BODY reached : read planes into RAM for ease of decompression */
if (!(screen.buffer=farmalloc(header.ckSize))) {
puts("Insufficient memory for picture allocation.");
fclose(fp);
return(NULL);
}
/* this special is necesary to overcome fread()'s 64K size limitation. */
BigRead(fp,screen.buffer,header.ckSize);
fclose(fp);
/* reduce 8-bit color register values to most significant 4 bits */
for (i=0;i<screen.colors;i++) {
screen.colormap[i][RGB_RED]/=16; /* BUG! >>=4 SHOULD WORK! */
screen.colormap[i][RGB_GREEN]/=16;
screen.colormap[i][RGB_BLUE]/=16;
}
screen.width=bmhd.w;
screen.height=bmhd.h;
screen.compression=bmhd.compression;
screen.mask=bmhd.masking;
/* add the masked plane to the interleaved plane cnt, if present */
screen.planes=bmhd.nPlanes+(screen.mask==mskHasMask);
return(&screen);
}
/* this buffer is TOO BIG to be declared locally! */
#define BUFSIZE 40000
char buf[BUFSIZE];
BigRead(FILE *file,unsigned char huge *buffer,unsigned long len)
{
/* Use this routine to perform fast reads into a HUGE buffer */
unsigned int size;
char *ptr;
while (len) {
if (len>=BUFSIZE) { /* 64K max buffer for fread() */
size=BUFSIZE;
SafeRead(file,buf,size);
}
else {
size=len;
SafeRead(file,buf,size);
}
len-=size; ptr=buf;
while (size--) *buffer++=*ptr++; /* local to HUGE buffer copy */
}
}
Reverse_Constant(value,size)
char value[];
int size;
{
int i;
char buf[sizeof(long)]; /* big enough to hold a char, short, or long */
movmem(value,&buf,size); /* Copy the Motorola value to our buffer */
size--; /* size must be from [0..n-1] for array processing */
for (i=0;i<=size;i++) value[i]=buf[size-i]; /* & copy it back, Intel-style */
}
Expand() /* pixel line decompress/deinterleave */
{
short plane,linelen,rowbytes,i,width=screen.width;
char n,*destbuf,huge *sourcebuf=screen.buffer;
/* roundup width to a multiple of 16 pixels, if necessary; important
for deinterleaving brushes correctly! */
if (width%16) width=(((width/16)+1)*16);
linelen=width/8;
for (i=0;i<screen.height;i++) { /* process n lines/screen */
for (plane=0;plane<screen.planes;plane++) { /* process n planes/line */
destbuf=&planes[plane][0];
if (screen.compression==cmpByteRun1) { /* compressed screen? */
rowbytes=linelen;
while (rowbytes) { /* unpack until 1 scan-line complete */
n=*sourcebuf++; /* fetch block run marker */
/* uncompressed block? copy n bytes verbatim */
if (n>=0) {
movmem(sourcebuf,destbuf,(unsigned int)++n);
rowbytes-=n;
destbuf+=n; sourcebuf+=n;
}
else { /* compressed block? expand n duplicate bytes */
n=-n+1; rowbytes-=n;
setmem(destbuf,n,(unsigned int)*sourcebuf++);
destbuf+=n;
}
} /* finish unpacking line */
}
else { /* uncompressed? just copy */
movmem(sourcebuf,destbuf,(unsigned int)linelen);
sourcebuf+=linelen; destbuf+=linelen;
}
} /* finish interleaved planes */
/* line assembled, so flush pixels out */
flush_pixels(i,linelen);
} /* finish lines */
}
flush_pixels(line,bytelen)
int line,bytelen;
{
int index,bit,p,color,px;
for (index=0;index<bytelen;index++) {
for (bit=0;bit<8;bit++) {
for (color=p=0;p<screen.planes;p++) {
if (planes[p][index] & (1<<bit))
color|=(1<<p);
}
/* Remap color according to closest palette available */
if (screen.mask==mskHasMask) color&=~(1<<p-1); /* remove mask effect on color */
if (remap) color=ega_remap[color];
/* Stretch lo-res pictures in the x direction if necessary.
Note that the pixels in a byte need to be spit out in
reverse order; i.e., the MSB represents the leftmost pixel. */
px=index*8+(7-bit);
/* Don't let the padded pixel width exceed the original picture width!
Any pixel padding is for the purposes of adhering to IFF
decompression ONLY. For display, we must remain true to the original
width. (otherwise, brushes will have the padding displayed!) */
if (px<screen.width) { /* the real, unpadded width */
if (!scaling || screen.width>LOWIDTH) putpixel(px,line,color);
else { /* stretch 320-wide pics to meet 640 resolution */
px<<=1;
putpixel(px,line,color);
putpixel(px+1,line,color);
}
}
} /* bit loop */
} /* byte loop */
}
remap_colors()
{
int color,i,delta,bestpick,bestdelta;
char sr,sg,sb,dr,dg,db,br,bg,bb;
static char ega_colors[16][3] = {
{ 0,0,0 }, /* black */
{ 0,0,10 }, /* blue */
{ 0,10,0 }, /* green */
{ 0,10,10 }, /* cyan */
{ 10,0,0 }, /* red */
{ 10,0,10 }, /* magenta */
{ 10,5,0 }, /* brown */
{ 10,10,10 }, /* lt. grey */
{ 5,5,5 }, /* dk. grey */
{ 5,5,15 }, /* lt. blue */
{ 5,15,5 }, /* lt. green */
{ 5,15,15 }, /* lt. cyan */
{ 15,5,5 }, /* lt. red */
{ 15,5,15 }, /* lt. magenta */
{ 15,15,5 }, /* yellow */
{ 15,15,15 } /* white */
};
/* step through the colors in our picture, remapping to the closest
possible equivalent in the EGA color scheme. This will also
perform color reduction if the picture has more bitplanes (colors)
than EGA will allow! */
for (color=0;color<screen.colors;color++) {
bestpick=0; bestdelta=0xfff;
for (i=0;i<16;i++) {
sr=screen.colormap[color][RGB_RED];
sg=screen.colormap[color][RGB_GREEN];
sb=screen.colormap[color][RGB_BLUE];
dr=ega_colors[i][RGB_RED];
dg=ega_colors[i][RGB_GREEN];
db=ega_colors[i][RGB_BLUE];
/* don't even ATTEMPT to remap colors that are an exact match! */
if (sr==dr && sg==dg && sb==db) {
bestpick=i;
break;
}
delta=
abs(bias(sr)-ega_colors[i][RGB_RED])+
abs(bias(sg)-ega_colors[i][RGB_GREEN])+
abs(bias(sb)-ega_colors[i][RGB_BLUE]);
if (delta<bestdelta) {
bestdelta=delta;
bestpick=i;
}
}
ega_remap[color]=bestpick;
if (debug) {
br=ega_colors[bestpick][RGB_RED];
bg=ega_colors[bestpick][RGB_GREEN];
bb=ega_colors[bestpick][RGB_BLUE];
printf("source color %d : %x,%x,%x remapped to EGA color %d (%x,%x,%x)\n",
color,sr,sg,sb,r_map[br]+g_map[bg]+b_map[bb],br,bg,bb);
}
}
}
bias(color)
int color;
{
/* reduce color choices to the EGA choices of none, normal or bright
simplifies the color remapping process to an exact match within
the EGA palette of primaries. */
if (color<5) return(NULL);
if (color<0x0b) return(0x0a);
return(0x0f);
}
OpenScreen()
{
/* our default DPaint-II palette of primaries */
static struct palettetype dpaint = {
16, { 0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63 }
};
int driver=EGA,mode=EGALO; /* 640 x 200 x 16 */
int result,i;
if (screen.height>LOHEIGHT) mode=EGAHI;
/* acknowledge the existence of our pre-linked EGA driver */
if (registerbgidriver(EGAVGA_driver) < 0) return(NULL);
initgraph(&driver,&mode,"");
result=graphresult();
if (result!=grOk) {
printf("Error : %s\n",grapherrormsg(result));
return(NULL);
}
/* save the TurboC default palette so we can restore it later */
getpalette(&palette);
/* We have one chance to display a picture in EGA mode without
remapping. Pictures in EGAHI with 16 colors or less can be
displayed simply by zapping the palette, which supports a
whopping 6 bits per color register. No need to do this for EGALO,
which only supports a 16-color palette to begin with.
NOTE #1 : We could display EGALO pictures in EGAHI resolution,
except that we would lose 50 lines of image expanding a 200-line
picture to 400 lines. Drawing would be twice as slow, and screen
captures would be twice the size.
NOTE #2 : Zapping color registers only preserves the most significant
two bits of RGB color present in the source image. This is fine for
IBM pics, but colors may be less pleasant than the AI remapping scheme
used when other pictures are displayed. Then again, they may be better.
*/
if (screen.planes <= 4 && mode==EGAHI && pal) {
for (i=0;i<screen.colors;i++) {
result=r_map[screen.colormap[i][RGB_RED]/4] +
g_map[screen.colormap[i][RGB_GREEN]/4] +
b_map[screen.colormap[i][RGB_BLUE]/4];
setpalette(i,result);
if (debug)
printf("Palette color %d = set to EGA %d (%d,%d,%d)\n",i,result,
screen.colormap[i][RGB_RED]/4,screen.colormap[i][RGB_GREEN]/4,
screen.colormap[i][RGB_BLUE]/4);
}
remap=0;
}
if (remap) {
setallpalette(&dpaint);
remap_colors();
}
/* Ideally, we would set do fill the whole screen with the background
color at this point. For full-screen pictures, this would not be
necessary; background pixels will be rendered correctly by hand.
Unfortunately, the Amiga & PC versions disagree on which color should
be the default background color. For this reason, pictures whose
mask = maskHasTransparentColor can only render opaquely. */
return(TRUE);
}
welcome()
{
puts(" Welcome to PC-View!\n\n"
"The IFF graphic file format, developed in joint development between\n"
"Electronic Arts and Commodore-Amiga, Inc. is the PC communities'\n"
"first attempt at a portable graphic standard. Find it in use on\n"
"the Commodore Amiga, Apple-II GS, IBM-PC, and perhaps others. Use\n"
"View to display otherwise undisplayable graphics (incl. VGA) on your PC!\n\n"
" Usage : view <file> [-s] [-p] [-d]\n\n"
"Options : -s disables auto horizontal scaling\n"
" -p disables auto direct palette mapping\n"
" -d displays information about your IFF picture\n\n"
"PC-View : Dallas Hodgson\n"
" 351 Kiely Bl, #B304\n"
" San Jose, Ca. 95129\n\n"
" Comments & Contributions gladly accepted.\n");
exit(100);
}
main(argc,argv)
int argc;
char *argv[];
{
char *fspec=0;
/* parse up command line */
while (--argc) {
++argv;
if (argv[0][0]=='-')
switch(toupper(argv[0][1])) {
case 'S': scaling=0; break;
case 'P': pal=0; break;
case 'D': debug=1; break;
default : welcome(); /* unrecognized switch */
}
else fspec=argv[0];
}
if (!fspec) welcome(); /* no filename specified */
puts(TITLE);
if (!ReadILBM(fspec)) exit(100);
if (debug) {
printf("Width=%d, Height=%d, Planes=%d, Colors=%d\n",
screen.width,screen.height,screen.planes,screen.colors);
printf("Compression=0x%x, Masking=0x%x, ViewModes=0x%lx\n",
screen.compression,screen.mask,screen.ViewModes);
putchar('\n');
}
if (OpenScreen()) {
Expand();
getchar();
setallpalette(&palette);
closegraph();
}
}